// CG_skel_w_MFC.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CG_skel_w_MFC.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// The one and only application object
#include "GL/glew.h"
#include "GL/freeglut.h"
#include "GL/freeglut_ext.h"
#include "vec.h"
#include "mat.h"
#include "InitShader.h"
#include "Scene.h"
#include "camera.h"
#include "Renderer.h"
#include <string>

#define BUFFER_OFFSET( offset )   ((GLvoid*) (offset))

#define FILE_OPEN 1
#define MAIN_DEMO 1
#define MAIN_ABOUT 2

Scene *scene;
Renderer *renderer;
GLfloat rotationStep=5;//degrees
GLfloat translationStep=0.1;//world coordinates, will now be called meters
GLfloat scalingRate = 1.1;
GLfloat planeMovementStep = 0.05;
GLfloat windowWidth;
GLfloat windowHeight;
GLfloat zoomStep=1.5;

int controlMode;
int keyboardControlMode = 0;

int last_x,last_y;
bool lb_down,rb_down,mb_down;
static bool centralizeModels = false;
static bool shrinkModels = false;
static vec3 mountingPoint = vec3(0,0,0);
static bool firstReshape = true;

static void toggleModelCentralization() {
	centralizeModels = !centralizeModels;
	cout << "centralizeModels = " << centralizeModels << endl;
}

static void toggleModelShrinking() {
	shrinkModels = !shrinkModels;
	cout << "shrinkModels = " << shrinkModels << endl;
}

static void adjustMountingPoint() {
	mountingPoint = scene->SuggestMountingPoint(); 
}

//----------------------------------------------------------------------------
// Callbacks

void display( void )
{
//Call the scene and ask it to draw itself
}

void reshape( int width, int height )
{
	windowWidth = width;
	windowHeight = height;
	if (firstReshape) {
		firstReshape = false;
		return;
	}
	scene->UpdateProjectionsForRatio( (GLfloat)windowWidth/(GLfloat)windowHeight);
	renderer->ReCreateBuffers(width,height);
	scene->redraw();
}

void toggleKBControlMode(const int numOfModes){
	keyboardControlMode ++;
	keyboardControlMode %= numOfModes;
}

void runtest(){
//NUMERIC ERROR TEST

	//int oldstep = rotationStep;
	//rotationStep=1;
	//cout<<"hi\n";
	//Camera* c = new Camera();
	//c->LookAt(vec3(-3,0,0),vec3(0,0,0),vec3(0,1,0));
	//c->Perspective(50,1,1,6);

	//scene->AddCamera(c);
	//const int meme = 30;
	//const int meme2 = 1;
	//for(int i=0;i<meme;i++){
	//	for(int j=0;j<meme2;j++){
	//		scene->RotateCamera(0,rotationStep,0);
	//	}
	//	//scene->redraw();
	//	for(int j=0;j<meme2;j++){
	//		scene->RotateCamera(rotationStep,0,0);
	//	}
	//	//scene->redraw();
	//	for(int j=0;j<meme2;j++){
	//		scene->RotateCamera(0,-rotationStep,0);
	//	}
	//	//scene->redraw();
	//	for(int j=0;j<meme2;j++){
	//		scene->RotateCamera(-rotationStep,0,0);
	//	}
	//	//scene->redraw();
	//}
	//rotationStep = oldstep;

//LIGHTS TEST
	cout<<"starting test"<<endl;
	Camera* c = new Camera();
	//c->LookAt(vec3(-3,0,0),vec3(0,0,0),vec3(0,1,0));
	//c->Perspective(50,1,1,20);
	//scene->AddCamera(c);
	//scene->PreviousCamera();
	//scene->loadOBJModel("C:\\Users\\MyPC\\Desktop\\graphics\\objects\\banana.obj");
	//scene->loadOBJModel("C:\\Users\\MyPC\\Desktop\\graphics\\objects\\crap.obj");
	toggleKBControlMode(2);

	

	vec3 ambient = vec3(0,0,0);
	vec3 diffuse = vec3(0,0,0);
	vec3 specular = vec3(0,0,0);
	vec4 location = vec4(0.2,0.2,0.2,1);
	cout<<"location input is: "<<location<<endl;
	LightSource* l1 = new PointLightSource(ambient,diffuse,specular,location);
	scene->AddLight(l1);
	LightSource* l2 = new PointLightSource(ambient,diffuse,specular,location+vec4(0.2,0.2,0.2,0));
	scene->AddLight(l2);
	scene->ToggleLightsDrawing();
	scene->redraw();
	//system("pause");
	scene->TranslateLight(0.3,0.3,0.3);
	scene->RotateLightAboutX(10);
	scene->RotateLightAboutY(20);
	scene->RotateLightAboutZ(15);
}


void keyboard( unsigned char key, int x, int y )
{

	const int numOfModes = 2;
	if (key == '\\'){
		toggleKBControlMode(numOfModes);
	}
	switch (keyboardControlMode){
	case 0:{//regular
		switch ( key ) {
		
		case 033: exit( EXIT_SUCCESS ); break;
		case 'a': scene->TranslateActiveModel(-translationStep,0,0); break;
		case 'd': scene->TranslateActiveModel(translationStep,0,0); break;
		case 'w': scene->TranslateActiveModel(0,translationStep,0); break;
		case 's': scene->TranslateActiveModel(0,-translationStep,0); break;
		case 'D': scene->SpinModel(0,rotationStep,0); break;
		case 'A': scene->SpinModel(0,-rotationStep,0); break;
		case 'S': scene->SpinModel(rotationStep,0,0); break;
		case 'W': scene->SpinModel(-rotationStep,0,0); break;
		case 'Q': scene->SpinModel(0,0,rotationStep); break;
		case 'E': scene->SpinModel(0,0,-rotationStep); break;
		case 'j': scene->RotateModelAboutY(-rotationStep); break;
		case 'l': scene->RotateModelAboutY(rotationStep); break;
		case 'i': scene->RotateModelAboutX(-rotationStep); break;
		case 'k': scene->RotateModelAboutX(rotationStep); break;
		case 'u': scene->RotateModelAboutZ(rotationStep); break;
		case 'o': scene->RotateModelAboutZ(-rotationStep); break;
		case '[': scene->NextModel(); break;
		case ']': scene->PreviousModel(); break;
		case '}': scene->NextCamera(); break;
		case '{': scene->PreviousCamera(); break;
		case 'c': scene->ToggleCameraDrawing(); break;
		case 'f': scene->FocusOnActiveModel(); break; //there lies a bug!
		case 'q': scene->TranslateActiveModel(0,0,translationStep); break;
		case 'e': scene->TranslateActiveModel(0,0,-translationStep); break;
		case 'n': scene->ToggleFaceNormals(); break;
		case 'm': scene->ToggleVertexNormals(); break;
		case 'b': scene->toggleBoundingBox(); break;
		case '<': scene->RotateCamera(0,rotationStep,0); break;
		case '>': scene->RotateCamera(0,-rotationStep,0); break;
		case '8': scene->RotateCamera(0,0,rotationStep); break;
		case '2': scene->RotateCamera(0,0,-rotationStep); break;
		case '4': scene->RotateCamera(rotationStep,0,0); break;
		case '6': scene->RotateCamera(-rotationStep,0,0); break;
		case 'z': scene->TranslateCamera(-translationStep,0,0); break;
		case 'x': scene->TranslateCamera(translationStep,0,0); break;
		case '+': scene->SymScaleActiveModel(1.2); break;
		case '-': scene->SymScaleActiveModel(0.8); break;
		case 'v': scene->addArk(); break;
		case 'r': scene->removeActiveModel(); break;
		case 'R': scene->removeAllModels(); break;
		case 't': runtest();break;
		case 'L': scene->ToggleLightsDrawing();break;
		default:
			std::cout << key << endl;
		}
	}break;
	case 1:{//unreal
		const int lightRotMagnifier = 100;
		switch ( key ) {
		case 'n': scene->ToggleFaceNormals(); break;
		case 'm': scene->ToggleVertexNormals(); break;
		case 'b': scene->toggleBoundingBox(); break;
		case 'w': scene->TranslateCameraForward(); break;
		case 's': scene->TranslateCameraBack(); break;
		case 'a': scene->TranslateCameraLeft(); break;
		case 'd': scene->TranslateCameraRight(); break;
		case 'c': scene->TranslateCameraDown(); break;
		case 'f': scene->TranslateCameraUp(); break;
		case 'q': scene->RotateCamera(0,0,rotationStep); break;
		case 'e': scene->RotateCamera(0,0,-rotationStep); break;
		case '}': scene->NextCamera(); break;
		case '{': scene->PreviousCamera(); break;
		case 'j': scene->RotateModelAboutY(-rotationStep); break;
		case 'l': scene->RotateModelAboutY(rotationStep); break;
		case 'i': scene->RotateModelAboutX(-rotationStep); break;
		case 'k': scene->RotateModelAboutX(rotationStep); break;
		case 'u': scene->RotateModelAboutZ(rotationStep); break;
		case 'o': scene->RotateModelAboutZ(-rotationStep); break;
		case '+': scene->SymScaleActiveModel(1.2); break;
		case '-': scene->SymScaleActiveModel(0.8); break;
		case 'v': scene->addArk(); break;
		case 'r': scene->removeActiveModel(); break;
		case 'R': scene->removeAllModels(); break;
		case 033: exit( EXIT_SUCCESS ); break;
		case '[': scene->NextModel(); break;
		case ']': scene->PreviousModel(); break;
		case 'L': scene->ToggleLightsDrawing();break;
		case '*': scene->NextLight();break;
		case '/': scene->PreviousLight();break;
		case 'x': scene->RotateLightAboutX(rotationStep*lightRotMagnifier);break;
		case 'X': scene->RotateLightAboutX(-rotationStep*lightRotMagnifier);break;
		case 'y': scene->RotateLightAboutY(rotationStep*lightRotMagnifier);break;
		case 'Y': scene->RotateLightAboutY(-rotationStep*lightRotMagnifier);break;
		case 'z': scene->RotateLightAboutZ(rotationStep*lightRotMagnifier);break;
		case 'Z': scene->RotateLightAboutZ(-rotationStep*lightRotMagnifier);break;
		}
	}break;
	default:{}
	}

	//redraw the scene...
	scene->redraw();
}

bool skipMotion = true;

void mouseWheel(int wheel, int direction, int x, int y) {
	//std::cout<< "Mouse weehl event at (x,y)= (" << x << "," << y << "; direction = " << direction << " ;wheel = " << wheel << endl;
	GLfloat stepTrans = direction*translationStep;
	GLfloat stepRot = direction*rotationStep;
	GLfloat scaleStep = direction > 0 ? scalingRate : 1.0/scalingRate;
	switch (controlMode) {
		case X_AXIS_TRANS:	scene->TranslateActiveModel(stepTrans,0,0); break;
		case Y_AXIS_TRANS:	scene->TranslateActiveModel(0,stepTrans,0); break;
		case Z_AXIS_TRANS:	scene->TranslateActiveModel(0,0,stepTrans); break;
		case X_AXIS_ROT:	scene->RotateModelAboutX(stepRot); break;
		case Y_AXIS_ROT:	scene->RotateModelAboutY(stepRot); break;
		case Z_AXIS_ROT:	scene->RotateModelAboutZ(stepRot); break;
		case X_AXIS_SPIN:	scene->SpinModel(stepRot,0,0); break;
		case Y_AXIS_SPIN:	scene->SpinModel(0,stepRot,0); break;
		case Z_AXIS_SPIN:	scene->SpinModel(0,0,stepRot); break;
		case X_AXIS_SCALE:	scene->ScaleActiveModel(scaleStep,1,1); break;
		case Y_AXIS_SCALE:	scene->ScaleActiveModel(1,scaleStep,1); break;
		case Z_AXIS_SCALE:	scene->ScaleActiveModel(1,1,scaleStep); break;
		case SYM_SCALE:		scene->SymScaleActiveModel(scaleStep); break;
		case X_CAM_MOVE:	scene->TranslateCamera(stepTrans,0,0); break;
		case Y_CAM_MOVE:	scene->TranslateCamera(0,stepTrans,0); break;
		case Z_CAM_MOVE:	scene->TranslateCamera(0,0,stepTrans); break;
		case X_CAM_SPIN:	scene->RotateCamera(stepRot,0,0); break;
		case Y_CAM_SPIN:	scene->RotateCamera(0,stepRot,0); break;
		case Z_CAM_SPIN:	scene->RotateCamera(0,0,stepRot); break;
		case CAM_ZOOM:		scene->Zoom(direction > 0 ? zoomStep : 1.0/zoomStep); break;
		case Z_NEAR_MOVE:	scene->MoveZNear(direction*planeMovementStep); break;
		case Z_FAR_MOVE:	scene->MoveZFar(direction*planeMovementStep); break;
		case NONE: return;
		default : AfxMessageBox(_T("Not supported operation!"));
	}
	scene->redraw();
}

void keyboardSpecial(int key, int x, int y) {
	switch (key) {
	case GLUT_KEY_F1: controlMode = X_AXIS_TRANS; break;
	case GLUT_KEY_F2: controlMode = Y_AXIS_TRANS; break;
	case GLUT_KEY_F3: controlMode = Z_AXIS_TRANS; break;
	case GLUT_KEY_F4: controlMode = X_AXIS_ROT; break;
	case GLUT_KEY_F5: controlMode = Y_AXIS_ROT; break;
	case GLUT_KEY_F6: controlMode = Z_AXIS_ROT; break;
	case GLUT_KEY_F7: controlMode = X_AXIS_SPIN; break;
	case GLUT_KEY_F8: controlMode = Y_AXIS_SPIN; break;
	case GLUT_KEY_F9: controlMode = Z_AXIS_SPIN; break;
	case GLUT_KEY_F10: toggleModelCentralization(); break;
	case GLUT_KEY_F11: toggleModelShrinking(); break;
	case GLUT_KEY_F12: adjustMountingPoint(); break;
	}
}

void mouse(int button, int state, int x, int y)
{
	//cout << __FUNCTION__ << endl;
	if (state == GLUT_UP) {
		skipMotion = true;
	}
	switch(button) {
		case GLUT_LEFT_BUTTON:
			lb_down = (state==GLUT_UP)?0:1;
			if (state==GLUT_DOWN) {
				skipMotion = false;
				last_x = x;
				last_y = y;
				int buffX = x;
				int buffY = windowHeight - y-1;
				renderer->printPixelData(buffX,buffY);
			}
			break;
		case GLUT_RIGHT_BUTTON:
			rb_down = (state==GLUT_UP)?0:1;
			break;
		case GLUT_MIDDLE_BUTTON:
			mb_down = (state==GLUT_UP)?0:1;	
			break;
	}

	// add your code
}

void motion(int x, int y)
{
	//cout << __FUNCTION__ << endl;
	// calc difference in mouse movement
	if (skipMotion) return;
	int dx=x-last_x;
	int dy=y-last_y;
	// update last x,y
	last_x=x;
	last_y=y;
	GLfloat sign = (dx > 0) ? 1 : -1;
	GLfloat stepTrans = sign*translationStep;
	GLfloat stepRot = sign*rotationStep;
	GLfloat scaleStep = sign > 0 ? scalingRate : 1.0/scalingRate;
	switch (keyboardControlMode){
	case 0:
		for (int i=0; i<abs(dx); i++) {
			switch (controlMode) {
				case X_AXIS_TRANS:	scene->TranslateActiveModel(stepTrans,0,0); break;
				case Y_AXIS_TRANS:	scene->TranslateActiveModel(0,stepTrans,0); break;
				case Z_AXIS_TRANS:	scene->TranslateActiveModel(0,0,stepTrans); break;
				case X_AXIS_ROT:	scene->RotateModelAboutX(stepRot); break;
				case Y_AXIS_ROT:	scene->RotateModelAboutY(stepRot); break;
				case Z_AXIS_ROT:	scene->RotateModelAboutZ(stepRot); break;
				case X_AXIS_SPIN:	scene->SpinModel(stepRot,0,0); break;
				case Y_AXIS_SPIN:	scene->SpinModel(0,stepRot,0); break;
				case Z_AXIS_SPIN:	scene->SpinModel(0,0,stepRot); break;
				case X_AXIS_SCALE:	scene->ScaleActiveModel(scaleStep,1,1); break;
				case Y_AXIS_SCALE:	scene->ScaleActiveModel(1,scaleStep,1); break;
				case Z_AXIS_SCALE:	scene->ScaleActiveModel(1,1,scaleStep); break;
				case SYM_SCALE:		scene->SymScaleActiveModel(scaleStep); break;
				case X_CAM_MOVE:	scene->TranslateCamera(stepTrans,0,0); break;
				case Y_CAM_MOVE:	scene->TranslateCamera(0,stepTrans,0); break;
				case Z_CAM_MOVE:	scene->TranslateCamera(0,0,stepTrans); break;
				case X_CAM_SPIN:	scene->RotateCamera(stepRot,0,0); break;
				case Y_CAM_SPIN:	scene->RotateCamera(0,stepRot,0); break;
				case Z_CAM_SPIN:	scene->RotateCamera(0,0,stepRot); break;
				case CAM_ZOOM:		scene->Zoom(sign > 0 ? zoomStep : 1.0/zoomStep); break;
				case Z_NEAR_MOVE:	scene->MoveZNear(sign*planeMovementStep); break;
				case Z_FAR_MOVE:	scene->MoveZFar(sign*planeMovementStep); break;
				case NONE: break;
				default : AfxMessageBox(_T("Not supported operation!"));
			}
			scene->redraw();
		}
		break;
	case 1:
			GLfloat signX = (dx >= 0) ? 1 : -1;
			GLfloat signY = (dy >= 0) ? 1 : -1;
			//scene->RotateCamera(signY*rotationStep*abs(dy),0,0);
			//scene->RotateCamera(0,signX*rotationStep*abs(dx),0);
			for (int i=0; i<abs(dy); i++) {
				scene->RotateCamera(signY*rotationStep,0,0);
				scene->redraw();
			}
			for (int i=0; i<abs(dx); i++) {
				scene->RotateCamera(0,signX*rotationStep,0);
				scene->redraw();
			}
		break;		
	}
	
}

void fileMenu(int id)
{
	switch (id)
	{
		case FILE_OPEN:
			CFileDialog dlg(TRUE,_T(".obj"),NULL,NULL,_T("*.obj|*.*"));
			if(dlg.DoModal()==IDOK)
			{
				std::string s((LPCTSTR)dlg.GetPathName());
				scene->loadOBJModel((LPCTSTR)dlg.GetPathName(),centralizeModels,shrinkModels,mountingPoint);
				scene->draw(); // let's see what the hell is gonna happen!
			}
			break;
	}
}

void mainMenu(int id)
{
	switch (id)
	{
	case MAIN_DEMO:
		scene->drawDemo();
		break;
	case MAIN_ABOUT:
		AfxMessageBox(_T("Computer Graphics"));
		break;
	}
}

static Pen readPen() {
	GLfloat red, green, blue;
	cout << "Please enter red,  green, blue parameters" << endl;
	cin >> red >> green >> blue;
	return Pen(red,green,blue);
}

void configMenu(int id) {
	Pen p;
	switch (id) {
	case CFG_ROT_STEP :
		//AfxMessageBox(_T("Please enter rotation step (degrees)...")); 
		cout << "Please enter rotation step (degrees)..." << endl;
		std::cin >> rotationStep;
		break;
	case CFG_TRANS_STEP:
		//AfxMessageBox(_T("Please enter translation step..."));
		cout << "Please enter translation step..." << endl;
		std::cin >> translationStep;
		break;
	case CFG_SCALE_STEP:
		//AfxMessageBox(_T("Please enter scaling delta"));
		cout << "Please enter scaling rate" << endl;
		std::cin >> scalingRate;
		break;
	case CFG_PLANE_STEP:
		//AfxMessageBox(_T("Please enter plane movement step"));
		cout << "Please enter plane movement step" << endl;
		cin >> planeMovementStep;
		break;
	case CFG_ACTIVE_PEN:
		p = readPen();
		scene->SetActivePen(p);
		scene->redraw();
		break;
	case CFG_PASSIVE_PEN:
		p = readPen();
		scene->SetPassivePen(p);
		scene->redraw();
		break;
	case CFG_ZOOM_STEP:
		cout << "Please enter zoom step" << endl;
		cin >> zoomStep;
		break;
	case CFG_CENTRALIZE:
		toggleModelCentralization();
		break;
	case CFG_SHRINK:
		toggleModelShrinking();
		break;
	case CFG_SET_MP: 
		adjustMountingPoint();
		break;
	case CFG_RESET_MP: 
		mountingPoint = vec3(0,0,0); 
		break;
	}
}

void modelControlMenu(int id) {
	skipMotion = true;
	controlMode = id;
}

void cameraControlMenu(int id) {
	skipMotion = true;
	controlMode = id;
}

void readCameraCoords(vec3 & eye, vec3 & at, vec3 & up) {
	std::cout << "Please enter \"eye\": (x,y,z) coords: " << endl;
	std::cin >> eye.x >> eye.y >> eye.z;
	std::cout << "Please enter \"at\": (x,y,z) coords :"  << endl;
	std::cin >> at.x >> at.y >> at.z;
	std::cout << "... same for up... " << endl;
	std::cin >> up.x >> up.y >> up.z;	
}

void readOrthographic( vec3 & centerOfPlane, GLfloat & width, GLfloat & depth) {
	std::cout << "Please enter center-of-plane coordinates...(x,y,z)" << endl;
	std::cin >> centerOfPlane.x >> centerOfPlane.y >> centerOfPlane.z;
	std::cout << "Please enter width of the cube..." << endl;
	std::cin >> width;
	std::cout << "Please enter depth of the cube (zNear - zFar)" << endl;
	std::cin >> depth;
}

void readPerspective(GLfloat & fov, GLfloat & zNear, GLfloat & zFar) {
	std::cout << "Please enter field of view,\n distance to near pleane,\n and distance to far plane" << endl;
	std::cin >> fov >> zNear >> zFar;
}

void readFrustum(vec2 & centerOfPlane, GLfloat & width, GLfloat & zNear, GLfloat & zFar) {
	std::cout << "Please enter center of projection plane coordinates (2D)" << endl;
	std::cin >> centerOfPlane.x >> centerOfPlane.y;
	std::cout << "Please enter width" << endl;
	std::cin >> width;
	while (width <= 0) {
		std::cout << "width must be positive..." << endl;
		std::cin >> width;
	}
	std::cout << "Please enter distance to near plane and distance to far plane..." << endl;
	std::cin >> zNear >> zFar;
}

void cameraLoadMenu(int id) {
	skipMotion = true;
	Camera * c = new Camera();
	vec3 eye, at, up;
	vec3 center;
	vec2 center2D;
	readCameraCoords(eye,at,up);
	c->LookAt(eye,at,up);
	
	GLfloat width;
	GLfloat height;
	GLfloat depth;
	GLfloat zNear, zFar;

	switch (id) {
	
	case CAMERA_LOAD_ORTH:
		readOrthographic(center,width,depth);
		// now create the orthographic projection!
		height = windowHeight*width/windowWidth;
		// create th orthographic cube...
		c->Ortho(	center.x - width/2, center.x + width/2,
			center.y - height/2,center.y + height/2,
			center.z, center.z - depth);
		break;
	case CAMERA_LOAD_FRUSTUM:
		readFrustum(center2D,width,zNear,zFar);
		height = windowHeight*width/windowWidth;
		c->Frustum(	center2D.x - width/2,center2D.x+width/2,
			center2D.y - height/2,center2D.y+height/2,zNear,zFar);
		break;
	case CAMERA_LOAD_PERSPECTIVE:
		GLfloat fov;
		GLfloat zNear, zFar;
		readPerspective(fov,zNear,zFar);
		GLfloat aspect = windowWidth/windowHeight;
		c->Perspective(DEG_TO_RAD(fov),aspect,zNear,zFar);
		break;
	}
	scene->AddCamera(c);
}

void lightsMenuProc(int id) {
	LightSource * ls;
	switch (id) {
	case LIGHT_ADD_POINT:
		ls = readPointLightSource();
		scene->addLightSource(ls);
		break;
	case LIGHT_ADD_PARALLEL:
		ls = readParallelLightSource();
		scene->addLightSource(ls);
		break;
	}
}

void initMenu()
{
	int menuFile = glutCreateMenu(fileMenu);
	glutAddMenuEntry("Open..",FILE_OPEN);
	int menuConfig = glutCreateMenu(configMenu);
	glutAddMenuEntry("Set rot. step",CFG_ROT_STEP);
	glutAddMenuEntry("Set trans. step", CFG_TRANS_STEP);
	glutAddMenuEntry("Set scale step", CFG_SCALE_STEP);
	glutAddMenuEntry("Set plane move step", CFG_PLANE_STEP);
	glutAddMenuEntry("Set Active Pen", CFG_ACTIVE_PEN);
	glutAddMenuEntry("Set Passive pen", CFG_PASSIVE_PEN);
	glutAddMenuEntry("Set Zoom Step", CFG_ZOOM_STEP);
	glutAddMenuEntry("Centalize models", CFG_CENTRALIZE);
	glutAddMenuEntry("Shrink models", CFG_SHRINK);
	glutAddMenuEntry("Adjust Mounting Point",CFG_SET_MP);
	glutAddMenuEntry("Reset Mounting Point",CFG_RESET_MP);
	int menuModelControl = glutCreateMenu(modelControlMenu); // this will be the main menu...
	glutAddMenuEntry("X-axis trans.",X_AXIS_TRANS);
	glutAddMenuEntry("Y-axis trans.",Y_AXIS_TRANS);
	glutAddMenuEntry("Z-axis trans.",Z_AXIS_TRANS);
	glutAddMenuEntry("X-axis rot.",X_AXIS_ROT);
	glutAddMenuEntry("Y-axis rot.",Y_AXIS_ROT);
	glutAddMenuEntry("Z-axis rot.",Z_AXIS_ROT);
	glutAddMenuEntry("X-axis spin",X_AXIS_SPIN);
	glutAddMenuEntry("Y-axis spin",Y_AXIS_SPIN);
	glutAddMenuEntry("Z-axis spin",Z_AXIS_SPIN);
	glutAddMenuEntry("X-axis scale",X_AXIS_SCALE);
	glutAddMenuEntry("Y-axis scale",Y_AXIS_SCALE);
	glutAddMenuEntry("Z-axis scale",Z_AXIS_SCALE);
	glutAddMenuEntry("Symmetric scale", SYM_SCALE);
	int menuCameraControl = glutCreateMenu(cameraControlMenu);
	glutAddMenuEntry("X-axis spin", X_CAM_SPIN);
	glutAddMenuEntry("Y-axis spin", Y_CAM_SPIN);
	glutAddMenuEntry("Z-axis spin", Z_CAM_SPIN);
	glutAddMenuEntry("X-axis move", X_CAM_MOVE);
	glutAddMenuEntry("Y-axis move", Y_CAM_MOVE);
	glutAddMenuEntry("Z-axis move", Z_CAM_MOVE);
	glutAddMenuEntry("Adjust zNear", Z_NEAR_MOVE);
	glutAddMenuEntry("Adjust Zfar", Z_FAR_MOVE);
	glutAddMenuEntry("Zoom",CAM_ZOOM);
	int menuLoadCamera = glutCreateMenu(cameraLoadMenu);
	glutAddMenuEntry("Load Camera (Orth.)",CAMERA_LOAD_ORTH);
	glutAddMenuEntry("Load Camera (Frustum)",CAMERA_LOAD_FRUSTUM);
	glutAddMenuEntry("Load Camera (Persp.)",CAMERA_LOAD_PERSPECTIVE);
	glutCreateMenu(mainMenu);
	glutAddSubMenu("File",menuFile);
	glutAddSubMenu("Config...",menuConfig);
	glutAddSubMenu("Model Control",menuModelControl);
	glutAddSubMenu("Cam. Control",menuCameraControl);
	glutAddSubMenu("Load Camera",menuLoadCamera);
	glutAddMenuEntry("Demo",MAIN_DEMO);
	glutAddMenuEntry("About",MAIN_ABOUT);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}

//----------------------------------------------------------------------------

int my_main( int argc, char **argv )
{
	//----------------------------------------------------------------------------
	// Initialize window
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_RGBA| GLUT_DOUBLE);
	glutInitWindowSize( 512, 512 );
	glutInitContextVersion( 3, 1 );
	glutInitContextProfile( GLUT_CORE_PROFILE );
	glutCreateWindow( "CG" );
	glewExperimental = GL_TRUE;
	glewInit();
	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		/* Problem: glewInit failed, something is seriously wrong. */
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
		/*		...*/
	}
	fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
	renderer = new Renderer(512,512);
	scene = new Scene(renderer);
	//----------------------------------------------------------------------------
	// Initialize Callbacks

	glutDisplayFunc( display );
	glutMouseWheelFunc(mouseWheel);
	glutKeyboardFunc( keyboard );
	glutSpecialFunc(keyboardSpecial);
	glutMouseFunc( mouse );
	glutMotionFunc ( motion );
	glutReshapeFunc( reshape );
	initMenu();
	glutMainLoop();
	delete scene;
	delete renderer;
	return 0;
}

CWinApp theApp; 

using namespace std;

int main( int argc, char **argv )
{
	int nRetCode = 0;
	
	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: error code to suit your needs
		_tprintf(_T("Fatal Error: MFC initialization failed\n"));
		nRetCode = 1;
	}
	else
	{
		my_main(argc, argv );
	}
	
	return nRetCode;
}